package com.shrct.businessprocess.budget.impl;

import com.google.common.base.Objects;
import com.google.common.collect.Iterables;
import com.shrct.businessprocess.budget.RCBudgetStatus;
import com.shrct.businessprocess.budget.RCBudgetTaskStatus;
import com.shrct.businessprocess.budget.RCCost4ACTItem;
import com.shrct.businessprocess.budget.RCCost4RemainItem;
import com.shrct.businessprocess.budget.RCCostBreakDown;
import com.shrct.businessprocess.budget.RCDirectCostRequest;
import com.shrct.businessprocess.budget.RCHasCostBudget;
import com.shrct.businessprocess.budget.RCHasCostBudgetCostRequest;
import com.shrct.businessprocess.budget.impl.RCBudgetImpl;
import com.shrct.businessprocess.budget.impl.RCDirectCostRequestImpl;
import com.shrct.businessprocess.budget.impl.RCHasCostBudgetCostRequestImpl;
import com.shrct.businessprocess.budget.proxy.RCHasCostBudgetProxy;
import com.shrct.businessprocess.money.Moneys;
import com.shrct.businessprocess.organization.RCEmployee;
import com.shrct.businessprocess.project.RCExchangeRate;
import com.shrct.businessprocess.project.RCProject;
import com.shrct.businessprocess.project.RCProjectMoney;
import com.shrct.businessprocess.project.RCProjectStat;
import com.shrct.businessprocess.project.RCRealMoney;
import com.shrct.businessprocess.purchase.RCPay;
import com.shrct.businessprocess.purchase.RCPayRequest;
import edu.fudan.langlab.domain.organization.Party;
import edu.fudan.langlab.domain.security.ISystemUserService;
import edu.fudan.mylang.common.NumberExtensions;
import edu.fudan.mylang.utils.DateUtil;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import javax.persistence.CascadeType;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
import javax.persistence.OneToMany;
import org.eclipse.xtext.xbase.lib.CollectionLiterals;
import org.eclipse.xtext.xbase.lib.DoubleExtensions;
import org.eclipse.xtext.xbase.lib.Functions.Function1;
import org.eclipse.xtext.xbase.lib.Functions.Function2;
import org.eclipse.xtext.xbase.lib.IterableExtensions;
import org.eclipse.xtext.xbase.lib.ObjectExtensions;
import org.eclipse.xtext.xbase.lib.Procedures.Procedure1;
import org.springframework.beans.factory.BeanFactory;

@Entity
@DiscriminatorValue("RCHASCOSTBUDGET_TYPE")
public abstract class RCHasCostBudgetImpl extends RCBudgetImpl implements RCHasCostBudget {
  public RCHasCostBudgetImpl() {
    super();
  }
  
  public RCHasCostBudgetImpl(final RCCostBreakDown cbd) {
    super( cbd);
    
  }
  
  @OneToMany(targetEntity = RCHasCostBudgetCostRequestImpl.class, cascade = { CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REMOVE }, mappedBy = "budget")
  private Collection<RCHasCostBudgetCostRequest> costRequests = new java.util.ArrayList<com.shrct.businessprocess.budget.RCHasCostBudgetCostRequest>();;
  
  public Collection<RCHasCostBudgetCostRequest> getCostRequests() {
    return this.costRequests;
  }
  
  public RCHasCostBudgetCostRequest createAndAddtoCostRequests() {
    getCostRequests().size();
    com.shrct.businessprocess.budget.RCHasCostBudgetCostRequest rCHasCostBudgetCostRequest = new com.shrct.businessprocess.budget.impl.RCHasCostBudgetCostRequestImpl(this);
    getObjectFactory().create(rCHasCostBudgetCostRequest);
    getCostRequests().add(rCHasCostBudgetCostRequest);
    return rCHasCostBudgetCostRequest;
    
  }
  
  public RCHasCostBudgetCostRequest createAndAddtoCostRequests(final Procedure1<RCHasCostBudgetCostRequest> updater) {
    getCostRequests().size();
    com.shrct.businessprocess.budget.RCHasCostBudgetCostRequest rCHasCostBudgetCostRequest = new com.shrct.businessprocess.budget.impl.RCHasCostBudgetCostRequestImpl(this);
    getObjectFactory().create(rCHasCostBudgetCostRequest);
    getCostRequests().add(rCHasCostBudgetCostRequest);
    return rCHasCostBudgetCostRequest;
    
  }
  
  public RCHasCostBudget removeAllCostRequests() {
    for(RCHasCostBudgetCostRequest obj : this.costRequests){
    	getObjectFactory().delete(obj);
    }
    this.costRequests.clear();
    return this;	
    
  }
  
  public RCHasCostBudget removeFromCostRequests(final RCHasCostBudgetCostRequest rCHasCostBudgetCostRequest) {
    this.costRequests.remove(rCHasCostBudgetCostRequest);
    getObjectFactory().delete(rCHasCostBudgetCostRequest);
    return this;
    
  }
  
  private RCBudgetStatus budgetStatus = RCBudgetStatus.unset;
  
  public RCBudgetStatus getBudgetStatus() {
    return this.budgetStatus;
  }
  
  public RCHasCostBudget setBudgetStatus(final RCBudgetStatus budgetStatus) {
    this.budgetStatus = budgetStatus;
    return this;			
    
  }
  
  public Collection<? extends RCPayRequest> getAllPayRequests() {
    return this.costRequests;
  }
  
  public Iterable<? extends RCPayRequest> getAllFinishedPayRequests() {
    Collection<? extends RCPayRequest> _allPayRequests = this.getAllPayRequests();
    final Function1<RCPayRequest,Boolean> _function = new Function1<RCPayRequest,Boolean>() {
        public Boolean apply(final RCPayRequest it) {
          boolean _and = false;
          Boolean _isFinished = it.getIsFinished();
          boolean _notEquals = (!Objects.equal(_isFinished, null));
          if (!_notEquals) {
            _and = false;
          } else {
            Boolean _isFinished_1 = it.getIsFinished();
            _and = (_notEquals && (_isFinished_1).booleanValue());
          }
          return Boolean.valueOf(_and);
        }
      };
    Iterable<? extends RCPayRequest> _filter = IterableExtensions.filter(_allPayRequests, _function);
    return _filter;
  }
  
  public RCRealMoney getTotalPaiedAmount() {
    Iterable<? extends RCPayRequest> _allFinishedPayRequests = this.getAllFinishedPayRequests();
    final Function1<RCPayRequest,Collection<RCPay>> _function = new Function1<RCPayRequest,Collection<RCPay>>() {
        public Collection<RCPay> apply(final RCPayRequest it) {
          Collection<RCPay> _purchasePays = it.getPurchasePays();
          return _purchasePays;
        }
      };
    Iterable<Collection<RCPay>> _map = IterableExtensions.map(_allFinishedPayRequests, _function);
    Iterable<RCPay> _flatten = Iterables.<RCPay>concat(_map);
    final Function1<RCPay,Double> _function_1 = new Function1<RCPay,Double>() {
        public Double apply(final RCPay it) {
          RCRealMoney _amount = it.getAmount();
          Double _hostAmount = _amount.toHostAmount();
          return _hostAmount;
        }
      };
    Iterable<Double> _map_1 = IterableExtensions.<RCPay, Double>map(_flatten, _function_1);
    RCCostBreakDown _cbd = this.getCbd();
    RCProject _project = _cbd.getProject();
    RCExchangeRate _defaultExchangeRate = _project.getDefaultExchangeRate();
    RCRealMoney _sumHostRealMoney = Moneys.sumHostRealMoney(_map_1, _defaultExchangeRate);
    return _sumHostRealMoney;
  }
  
  public RCDirectCostRequest createDirectCostRequest(final Procedure1<? super RCDirectCostRequest> init) {RCDirectCostRequest rCDirectCostRequest=RCDirectCostRequestImpl.create(this,getObjectFactory());
    final Procedure1<RCDirectCostRequest> _function = new Procedure1<RCDirectCostRequest>() {
        public void apply(final RCDirectCostRequest it) {
          BeanFactory _beanFactory = RCHasCostBudgetImpl.this.getBeanFactory();
          ISystemUserService _bean = _beanFactory.<ISystemUserService>getBean(ISystemUserService.class);
          Party _currentUserAsParty = _bean.getCurrentUserAsParty();
          it.setRequester(((RCEmployee) _currentUserAsParty));
          it.setIsFinished(Boolean.valueOf(true));
          Date _now = DateUtil.now();
          it.setFinishDate(_now);
          RCPay _createAndAddtoPurchasePays = it.createAndAddtoPurchasePays(RCHasCostBudgetImpl.this);
          final Procedure1<RCPay> _function = new Procedure1<RCPay>() {
              public void apply(final RCPay it) {
                Date _now = DateUtil.now();
                it.setPayDate(_now);
              }
            };
          ObjectExtensions.<RCPay>operator_doubleArrow(_createAndAddtoPurchasePays, _function);
          init.apply(it);
          RCCostBreakDown _cbd = RCHasCostBudgetImpl.this.getCbd();
          RCProject _project = _cbd.getProject();
          RCProjectStat _stat = _project.getStat();
          _stat.updateInfo();
        }
      };
    RCDirectCostRequest _doubleArrow = ObjectExtensions.<RCDirectCostRequest>operator_doubleArrow(rCDirectCostRequest, _function);
    return _doubleArrow;
  }
  
  public void updateDirectCostRequest(final RCDirectCostRequest value, final Procedure1<? super RCDirectCostRequest> updater) {
    updater.apply(value);
    RCCostBreakDown _cbd = this.getCbd();
    RCProject _project = _cbd.getProject();
    RCProjectStat _stat = _project.getStat();
    _stat.updateInfo();
  }
  
  public void deleteDirectCostRequest(final RCDirectCostRequest value) {getObjectFactory().delete(value);
    
    RCCostBreakDown _cbd = this.getCbd();
    RCProject _project = _cbd.getProject();
    RCProjectStat _stat = _project.getStat();
    _stat.updateInfo();
  }
  
  public RCProjectMoney getActualPurchaseTax() {
    RCProjectMoney _xblockexpression = null;
    {
      Iterable<RCCost4ACTItem> _cost4ACItems = this.getCost4ACItems();
      final Function1<RCCost4ACTItem,Double> _function = new Function1<RCCost4ACTItem,Double>() {
          public Double apply(final RCCost4ACTItem it) {
            Double _amount = it.getAmount();
            Double _taxRate = it.getTaxRate();
            Double _nullsafe = NumberExtensions.nullsafe(_taxRate);
            double _divide = ((_nullsafe).doubleValue() / 100);
            double _plus = (1 + _divide);
            double _divide_1 = ((_amount).doubleValue() / _plus);
            Double _taxRate_1 = it.getTaxRate();
            Double _nullsafe_1 = NumberExtensions.nullsafe(_taxRate_1);
            double _multiply = (_divide_1 * (_nullsafe_1).doubleValue());
            double _divide_2 = (_multiply / 100);
            return Double.valueOf(_divide_2);
          }
        };
      Iterable<Double> _map = IterableExtensions.<RCCost4ACTItem, Double>map(_cost4ACItems, _function);
      final Function2<Double,Double,Double> _function_1 = new Function2<Double,Double,Double>() {
          public Double apply(final Double d1, final Double d2) {
            double _plus = DoubleExtensions.operator_plus(d1, d2);
            return Double.valueOf(_plus);
          }
        };
      Double _reduce = IterableExtensions.<Double>reduce(_map, _function_1);
      Double _nullsafe = NumberExtensions.nullsafe(_reduce);
      Iterable<RCCost4RemainItem> _rCCost4RemainItems = this.getRCCost4RemainItems();
      final Function1<RCCost4RemainItem,Boolean> _function_2 = new Function1<RCCost4RemainItem,Boolean>() {
          public Boolean apply(final RCCost4RemainItem it) {
            Double _amount = it.getAmount();
            boolean _greaterThan = ((_amount).doubleValue() > 0);
            return Boolean.valueOf(_greaterThan);
          }
        };
      Iterable<RCCost4RemainItem> _filter = IterableExtensions.<RCCost4RemainItem>filter(_rCCost4RemainItems, _function_2);
      final Function1<RCCost4RemainItem,Double> _function_3 = new Function1<RCCost4RemainItem,Double>() {
          public Double apply(final RCCost4RemainItem it) {
            Double _amount = it.getAmount();
            Double _taxRate = it.getTaxRate();
            Double _nullsafe = NumberExtensions.nullsafe(_taxRate);
            double _divide = ((_nullsafe).doubleValue() / 100);
            double _plus = (1 + _divide);
            double _divide_1 = ((_amount).doubleValue() / _plus);
            Double _taxRate_1 = it.getTaxRate();
            Double _nullsafe_1 = NumberExtensions.nullsafe(_taxRate_1);
            double _multiply = (_divide_1 * (_nullsafe_1).doubleValue());
            double _divide_2 = (_multiply / 100);
            return Double.valueOf(_divide_2);
          }
        };
      Iterable<Double> _map_1 = IterableExtensions.<RCCost4RemainItem, Double>map(_filter, _function_3);
      final Function2<Double,Double,Double> _function_4 = new Function2<Double,Double,Double>() {
          public Double apply(final Double d1, final Double d2) {
            double _plus = DoubleExtensions.operator_plus(d1, d2);
            return Double.valueOf(_plus);
          }
        };
      Double _reduce_1 = IterableExtensions.<Double>reduce(_map_1, _function_4);
      Double _nullsafe_1 = NumberExtensions.nullsafe(_reduce_1);
      final double amount = DoubleExtensions.operator_plus(_nullsafe, _nullsafe_1);
      RCCostBreakDown _cbd = this.getCbd();
      RCProject _project = _cbd.getProject();
      RCProjectMoney _zeroAmount = _project.getZeroAmount();
      final Procedure1<RCProjectMoney> _function_5 = new Procedure1<RCProjectMoney>() {
          public void apply(final RCProjectMoney it) {
            it.setAmount(Double.valueOf(amount));
          }
        };
      RCProjectMoney _doubleArrow = ObjectExtensions.<RCProjectMoney>operator_doubleArrow(_zeroAmount, _function_5);
      _xblockexpression = (_doubleArrow);
    }
    return _xblockexpression;
  }
  
  public RCProjectMoney getTotalPayRequestedAmount() {
    Collection<? extends RCPayRequest> _allPayRequests = this.getAllPayRequests();
    final Function1<RCPayRequest,RCProjectMoney> _function = new Function1<RCPayRequest,RCProjectMoney>() {
        public RCProjectMoney apply(final RCPayRequest it) {
          RCProjectMoney _amount = it.getAmount();
          return _amount;
        }
      };
    Iterable<RCProjectMoney> _map = IterableExtensions.map(_allPayRequests, _function);
    RCCostBreakDown _cbd = this.getCbd();
    RCProject _project = _cbd.getProject();
    RCExchangeRate _defaultExchangeRate = _project.getDefaultExchangeRate();
    RCProjectMoney _sum = Moneys.sum(_map, _defaultExchangeRate);
    return _sum;
  }
  
  public Iterable<RCCost4ACTItem> getCost4ACItems() {
    Iterable<? extends RCPayRequest> _allFinishedPayRequests = this.getAllFinishedPayRequests();
    final Function1<RCPayRequest,RCCost4ACTItem> _function = new Function1<RCPayRequest,RCCost4ACTItem>() {
        public RCCost4ACTItem apply(final RCPayRequest request) {
          RCCost4ACTItem _rCCost4ACTItem = new RCCost4ACTItem();
          final Procedure1<RCCost4ACTItem> _function = new Procedure1<RCCost4ACTItem>() {
              public void apply(final RCCost4ACTItem it) {
                it.setBudget(RCHasCostBudgetImpl.this);
                String _entityName = request.getEntityName();
                it.setTitle(_entityName);
                RCRealMoney _totalPaidAmount = request.getTotalPaidAmount();
                Double _hostAmount = _totalPaidAmount.toHostAmount();
                it.setAmount(_hostAmount);
                Double _taxRate = request.getTaxRate();
                it.setTaxRate(_taxRate);
                Date _finishDate = request.getFinishDate();
                it.setDate(_finishDate);
              }
            };
          RCCost4ACTItem _doubleArrow = ObjectExtensions.<RCCost4ACTItem>operator_doubleArrow(_rCCost4ACTItem, _function);
          return _doubleArrow;
        }
      };
    Iterable<RCCost4ACTItem> _map = IterableExtensions.map(_allFinishedPayRequests, _function);
    return _map;
  }
  
  public Iterable<RCCost4RemainItem> getRCCost4RemainItems() {
    Iterable<RCCost4RemainItem> _xblockexpression = null;
    {
      Boolean _seemsFinished = this.seemsFinished();
      if ((_seemsFinished).booleanValue()) {
        return CollectionLiterals.<RCCost4RemainItem>newArrayList();
      }
      RCCost4RemainItem _rCCost4RemainItem = new RCCost4RemainItem();
      final Procedure1<RCCost4RemainItem> _function = new Procedure1<RCCost4RemainItem>() {
          public void apply(final RCCost4RemainItem it) {
            it.setBudget(RCHasCostBudgetImpl.this);
            String _entityName = RCHasCostBudgetImpl.this.getEntityName();
            it.setTitle(_entityName);
            Double _remainAmount = RCHasCostBudgetImpl.this.getRemainAmount();
            it.setAmount(_remainAmount);
            Double _netTaxRate = RCHasCostBudgetImpl.this.getNetTaxRate();
            it.setTaxRate(_netTaxRate);
          }
        };
      RCCost4RemainItem _doubleArrow = ObjectExtensions.<RCCost4RemainItem>operator_doubleArrow(_rCCost4RemainItem, _function);
      ArrayList<RCCost4RemainItem> _newArrayList = CollectionLiterals.<RCCost4RemainItem>newArrayList(_doubleArrow);
      final Function1<RCCost4RemainItem,Boolean> _function_1 = new Function1<RCCost4RemainItem,Boolean>() {
          public Boolean apply(final RCCost4RemainItem it) {
            Double _amount = it.getAmount();
            boolean _greaterThan = ((_amount).doubleValue() > 0);
            return Boolean.valueOf(_greaterThan);
          }
        };
      Iterable<RCCost4RemainItem> _filter = IterableExtensions.<RCCost4RemainItem>filter(_newArrayList, _function_1);
      _xblockexpression = (_filter);
    }
    return _xblockexpression;
  }
  
  public RCProjectMoney getActualCostAmount() {
    RCCostBreakDown _cbd = this.getCbd();
    RCProject _project = _cbd.getProject();
    RCProjectMoney _zeroAmount = _project.getZeroAmount();
    final Procedure1<RCProjectMoney> _function = new Procedure1<RCProjectMoney>() {
        public void apply(final RCProjectMoney it) {
          Iterable<RCCost4ACTItem> _cost4ACItems = RCHasCostBudgetImpl.this.getCost4ACItems();
          final Function1<RCCost4ACTItem,Double> _function = new Function1<RCCost4ACTItem,Double>() {
              public Double apply(final RCCost4ACTItem it) {
                Double _amount = it.getAmount();
                return _amount;
              }
            };
          Iterable<Double> _map = IterableExtensions.<RCCost4ACTItem, Double>map(_cost4ACItems, _function);
          final Function2<Double,Double,Double> _function_1 = new Function2<Double,Double,Double>() {
              public Double apply(final Double d1, final Double d2) {
                double _plus = DoubleExtensions.operator_plus(d1, d2);
                return Double.valueOf(_plus);
              }
            };
          Double _reduce = IterableExtensions.<Double>reduce(_map, _function_1);
          Double _nullsafe = NumberExtensions.nullsafe(_reduce);
          it.setAmount(_nullsafe);
        }
      };
    RCProjectMoney _doubleArrow = ObjectExtensions.<RCProjectMoney>operator_doubleArrow(_zeroAmount, _function);
    return _doubleArrow;
  }
  
  public Boolean seemsFinished() {
    boolean _xifexpression = false;
    boolean _equals = Objects.equal(this.budgetStatus, RCBudgetStatus.unset);
    if (_equals) {
      _xifexpression = false;
    } else {
      boolean _equals_1 = Objects.equal(this.budgetStatus, RCBudgetStatus.finished);
      _xifexpression = _equals_1;
    }
    return Boolean.valueOf(_xifexpression);
  }
  
  public RCBudgetTaskStatus getBudgetTaskStatus() {
    RCBudgetTaskStatus _xifexpression = null;
    boolean _and = false;
    RCProjectMoney _contractPrice = this.getContractPrice();
    Double _amount = _contractPrice.getAmount();
    boolean _equals = ((_amount).doubleValue() == 0d);
    if (!_equals) {
      _and = false;
    } else {
      RCProjectMoney _netPrice = this.getNetPrice();
      Double _amount_1 = _netPrice.getAmount();
      boolean _equals_1 = ((_amount_1).doubleValue() == 0);
      _and = (_equals && _equals_1);
    }
    if (_and) {
      _xifexpression = RCBudgetTaskStatus.unknown;
    } else {
      RCBudgetTaskStatus _xifexpression_1 = null;
      Boolean _seemsFinished = this.seemsFinished();
      if ((_seemsFinished).booleanValue()) {
        _xifexpression_1 = RCBudgetTaskStatus.finished;
      } else {
        _xifexpression_1 = RCBudgetTaskStatus.unfinished;
      }
      _xifexpression = _xifexpression_1;
    }
    return _xifexpression;
  }
  
  public RCHasCostBudgetProxy toProxy() {
    com.shrct.businessprocess.budget.proxy.RCHasCostBudgetProxy proxy = new com.shrct.businessprocess.budget.proxy.RCHasCostBudgetProxy();
    proxy.setId(this.getId());
    if(this instanceof edu.fudan.mylang.pf.INamedModelObject){
    	proxy.setName(((edu.fudan.mylang.pf.INamedModelObject)this).getEntityName());
    }
    return proxy;
    
  }
}
